#include "ScenesManager.h"
#include <stdio.h>
#include "FileManager.h"
#include "Object.h"
#include "Camera.h"
#include "ResourcesManager.h"
#include "Matrix.h"
#include "Shader.h"

extern ResourcesManager* resManager;
Camera* sceneCamera = NULL;
Shader* shad = NULL;

union ColorDataConverter
{
    int iValue;
    struct
	{
		unsigned char r, g, b, a;
	};
};
ColorDataConverter unionObjectColor;

//---------------------------------------------------
/// Constructor
//---------------------------------------------------
ScenesManager::ScenesManager(void)
{
	m_objects = 0;
	m_cameras = 0;

	m_numOfObjects = 0;
	m_numOfCameras = 0;
}

//---------------------------------------------------
/// Init
//---------------------------------------------------
void ScenesManager::Init(const char* file)
{
	//ResourcesManager* resManager = ResourcesManager::GetInstance();

	FILE* f = FileManager::GetInstance()->Open(file, "r");

	if (f == NULL)
	{
		LOGE("Can't not open Scene Manager file\n");
		return;
	}

	char id[MAX];
	char model[MAX];	
	char texture[MAX];
	char shader[MAX];
	Vector3 pos, rot, sca;
	int N;

	// OBJECTS
	fscanf(f, "#Object: %d\n", &N);
	m_numOfObjects = N;
	m_objects = new Object* [m_numOfObjects];
	fscanf(f, "%*s %*s %*s %*s %*s %*s %*s\n");
	for(int i = 0; i < m_numOfObjects; ++i)
	{
		// id  - model - texture - shader
		fscanf(f, "%s %s %s %s", id, model, texture, shader);
		// position - rotation - scale
		fscanf(f, "%f, %f, %f", &pos.x, &pos.y, &pos.z);
		fscanf(f, "%f, %f, %f", &rot.x, &rot.y, &rot.z);
		fscanf(f, "%f, %f, %f\n", &sca.x, &sca.y, &sca.z);
		//
		m_objects[i] = new Object();
		m_objects[i]->Init(id, pos, rot, sca, resManager->GetTextureById(texture), resManager->GetModelById(model), resManager->GetShaderById(shader));
	}

	// CAMERA
	fscanf(f, "#Camera: %d\n", &N);
	m_numOfCameras = N;
	m_cameras = new Camera* [m_numOfCameras];

	fscanf(f,"%*s %*s %*s %*s %*s %*s\n");
	GLfloat fovY, nearPlane, farPlane, speed;
	for(int i = 0; i < m_numOfCameras; ++i)
	{
		// id - fov - nearPlane - farPlane - speed
		fscanf(f, "%s %f %f %f %f", id, &fovY, &nearPlane, &farPlane, &speed);
		m_cameras[i] = new Camera();
		m_cameras[i]->Init(id, Vector3(0.0f, 0.0f, 0.0f), fovY * k_Pi / 180, ScreenSolution::GetInstance()->GetRatio(), nearPlane, farPlane, speed);
	}

	sceneCamera = GetCameraById("sceneCam");
	shad = resManager->GetShaderById("sShad");
	// CLOSE FILE
	fclose(f);
}

//---------------------------------------------------
/// UPDATE
//---------------------------------------------------
void ScenesManager::Update()
{
	sceneCamera->Update();
}

//---------------------------------------------------
/// DRAW
//---------------------------------------------------
void ScenesManager::Draw()
{
	// clear screen
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// calculate View-Project Matrix
	Matrix vpMatrix = sceneCamera->CalculateVPMatrix();
	
	// draw objects
	for(int i = 0; i < m_numOfObjects; ++i)
	{
		m_objects[i]->Draw(vpMatrix);
	}
	
}


void ScenesManager::DrawWithColor()
{
	// calculate View-Project Matrix
	Matrix vpMatrix = sceneCamera->CalculateVPMatrix();

	// draw objects
	for(int i = 0; i < m_numOfObjects; ++i)
	{
		Shader* oldShader = m_objects[i]->GetShader();

		m_objects[i]->SetShader(shad);
		// convert color data int 4 byte -> Vector4
		unionObjectColor.iValue = i;
		Vector4 color((float) unionObjectColor.r / 255, 
											 (float) unionObjectColor.g / 255, 
											 (float) unionObjectColor.b / 255, 
											 (float) unionObjectColor.a / 255);
		m_objects[i]->Draw(vpMatrix, color);

		m_objects[i]->SetShader(oldShader);
	}
	
}

Object* ScenesManager::ObjectDetection(int a)
{
	Object* obj = NULL;

	if (a >= m_numOfObjects)
	{
		LOGI("Object not identified!\n");
	}
	else
	{
		obj = m_objects[a];
		LOGI("touch on %s \n", obj->GetId());
	}

	return obj;
}

//---------------------------------------------------
/// Get Object by id
//---------------------------------------------------
Object* ScenesManager::GetObjectById(const char* id)
{
	Object* object = NULL;
	for(int i = 0; i < m_numOfObjects; ++i)
	{
		if(strcmp(m_objects[i]->GetId(), id) == 0)
		{
			object = m_objects[i];
			break;
		}
	}

	return object;
}

//---------------------------------------------------
/// Get Camera by id
//---------------------------------------------------
Camera* ScenesManager::GetCameraById(const char * id)
{
	Camera* cam = NULL;
	for(int i = 0; i < m_numOfCameras; ++i)
	{
		if(strcmp(m_cameras[i]->GetId(), id) == 0)
		{
			cam = m_cameras[i];
			break;
		}
	}

	return cam;
}

//---------------------------------------------------
/// GET INSTANCE
//---------------------------------------------------
ScenesManager* ScenesManager::s_Instance = 0;
ScenesManager* ScenesManager::GetInstance()
{
	if (!s_Instance)
	{
		s_Instance = new ScenesManager();
	}
	return s_Instance;
}

//---------------------------------------------------
/// DESTROY INSTANCE
//---------------------------------------------------
void ScenesManager::Destroy()
{
	if (s_Instance )
	{
		delete s_Instance;
		s_Instance = NULL;
	}
}

//---------------------------------------------------
/// Destructor
//---------------------------------------------------
ScenesManager::~ScenesManager(void)
{
	for(int i = 0; i < m_numOfCameras; ++i)
	{
		SAFE_DEL(m_cameras[i]);
	}
	SAFE_DEL_ARRAY(m_cameras);

	for(int i = 0; i < m_numOfObjects; ++i)
	{
		SAFE_DEL(m_objects[i]);
	}
	SAFE_DEL_ARRAY(m_objects);
}
